package cumeo89.chii.client.wikt;

import static cumeo89.chii.client.entry.Constants.*;
import static cumeo89.chii.client.util.StringUtil.*;
import static cumeo89.chii.client.util.XMLUtil.*;

import com.google.gwt.xml.client.Attr;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.Node;
import com.google.gwt.xml.client.NodeList;

import cumeo89.chii.client.Chii;
import cumeo89.chii.client.ChiiListener;
import cumeo89.chii.client.entry.Constants;
import cumeo89.chii.client.entry.EntryModel;
import cumeo89.chii.client.entry.EntryModelListener;
import cumeo89.chii.client.util.JSStringArray;
import cumeo89.chii.client.util.MyArrays;
import cumeo89.chii.client.util.StringUtil;

public class WiktionaryTool implements ChiiListener, EntryModelListener {

	private static final String ITALIC = "''";
	private static final String BOLD = "'''";

	private boolean inWiktionaryTool = false;

	public void chiiShutedDown(Chii chii) {
		// TODO Auto-generated method stub

	}

	public String chiiWillShutDown(Chii chii) {
		// TODO Auto-generated method stub
		return null;
	}

	public void entryLoaded(Chii chii) {
		chii.getModel().removeEntryModelListener(this);
		chii.getModel().addEntryModelListener(this);
	}

	public void attrRemoved(EntryModel model, Element element, Attr attr) {
		if (inWiktionaryTool) {
			return;
		}
		try {
		} finally {
			inWiktionaryTool = false;
		}
	}

	public void attrSetted(EntryModel model, Element element, Attr attr,
			String oldValue) {
		if (inWiktionaryTool) {
			return;
		}
		try {
		} finally {
			inWiktionaryTool = false;
		}
	}

	public void documentUpdated(EntryModel model) {
		if (inWiktionaryTool) {
			return;
		}
		try {
		} finally {
			inWiktionaryTool = false;
		}
	}

	public void nodeInserted(EntryModel model, Node node) {
		if (inWiktionaryTool) {
			return;
		}
		try {
		} finally {
			inWiktionaryTool = false;
		}
	}

	public void nodeRemoved(EntryModel model, Node node, Node parent,
			Node refChild) {
		if (inWiktionaryTool) {
			return;
		}
		try {
			inWiktionaryTool = true;
			if (node.getNodeType() == Node.ELEMENT_NODE) {
				// remove categories
				Element elem = (Element) node;
				if (E_POS.equals(elem.getTagName())) {
					removeCategory(model, ((Element) parent)
							.getAttribute(A_LANG_CODE), elem
							.getAttribute(A_POS_CODE));
				}
				NodeList poss = elem.getElementsByTagName(E_POS);
				for (int i = 0; i < poss.getLength(); i++) {
					Element pos = (Element) poss.item(i);
					Element lang = (Element) pos.getParentNode();
					removeCategory(model, lang.getAttribute(A_LANG_CODE), pos
							.getAttribute(A_POS_CODE));
				}
			}
		} finally {
			inWiktionaryTool = false;
		}
	}

	public void nodeUpdated(EntryModel model, Node node, String oldValue) {
		if (inWiktionaryTool) {
			return;
		}
		try {
			inWiktionaryTool = true;
			if (node.getNodeType() == Node.ATTRIBUTE_NODE) {
				Attr attr = (Attr) node;
				Element owner = getElement(attr);
				String name = attr.getName();
				String value = attr.getValue();
				if (A_LANG_CODE.equals(name)
						&& E_LANG.equals(owner.getTagName())
						&& owner.getElementsByTagName(E_PRONUNCIATION)
								.getLength() <= 0
						&& VIETNAMESE_CODE.equals(node.getNodeValue())) {
					StringBuilder ipaCode = new StringBuilder(
							"* [[Wiktionary:IPA|IPA]]: {{IPA|/");
					JSStringArray words = StringUtil.split(model.getTitle(),
							"\\s+");
					for (int i = 0; i < words.length(); i++) {
						String word = words.get(i);
						ipaCode.append("{{VieIPA");
						for (int j = 0; j < word.length(); j++) {
							ipaCode.append("|").append(word.charAt(j));
						}
						if (i < words.length() - 1)
							ipaCode.append(" ");
					}
					ipaCode.append("/}}");

					Element pron = model.getDocument().createElement(
							Constants.E_PRONUNCIATION);
					pron.appendChild(model.getDocument().createTextNode(
							ipaCode.toString()));
					model.appendChild(owner, pron);
				} else if (A_POS_CODE.equals(name)
						&& E_POS.equals(owner.getTagName())) {
					String langCode = ((Element) owner.getParentNode())
							.getAttribute(A_LANG_CODE);
					removeCategory(model, langCode, oldValue);
					addCategory(model, langCode, value);
					// set spelling
					if (!owner.hasAttribute(A_POS_SPELL)
							|| owner.getAttribute(A_POS_SPELL).trim().length() <= 0) {
						if (ENGLISH_CODE.equals(langCode)
								&& NOUN_CODE.equals(value)) {
							model.setAttribute(owner, A_POS_SPELL,
									getEngNounTemplate(model.getTitle()));
						} else if (ENGLISH_CODE.equals(langCode)
								&& ADJACTIVE_CODE.equals(value)) {
							model.setAttribute(owner, A_POS_SPELL,
									"{{eng-adj}}");
						} else if (ENGLISH_CODE.equals(langCode)
								&& VERB_CODES.equals(value)) {
							model.setAttribute(owner, A_POS_SPELL,
									"{{eng-verb}}");
						} else {
							model.setAttribute(owner, A_POS_SPELL, BOLD
									+ model.getTitle() + BOLD);
						}
					}
				} else if (A_EXAMPLE_CONTENT.equals(name)) {
					value = value.trim().replaceAll("'", "");
					value = ITALIC + value + ITALIC;
					value = value.replaceAll(model.getTitle(), BOLD
							+ model.getTitle() + BOLD);
					model.setValue(attr, value);
				}
			}
		} finally {
			inWiktionaryTool = false;
		}
	}

	private String getEngNounTemplate(String title) {
		StringBuffer sb = new StringBuffer("{{eng-noun|");
		
		// nhung quy tac nay k phai luon dung trong moi truong hop
		if (title.endsWith("y")
				&& !StringUtil.isEnglishVowel(title.charAt(title.length() - 2))) {
			sb.append(title.substring(0, title.length() - 1)).append("ies");
		} else if (title.endsWith("f")) {
			sb.append(title.substring(0, title.length() - 1)).append("ves");
		} else if (title.endsWith("o")) {
			sb.append(title).append("es");
		} else {
			sb.append(title).append("s");
		}

		JSStringArray sgs = StringUtil.split(title, "\\s+");
		if (sgs.length() > 0) {
			sb.append("|sg=");
			for (int i = 0; i < sgs.length(); i++) {
				sb.append("[[").append(sgs.get(i)).append("]] ");
			}
			sb.delete(sb.length() - 1, sb.length());
		}

		sb.append("}}");

		return sb.toString();
	}

	/*
	 * Utilities
	 */
	private void addCategory(EntryModel model, String langCode, String posCode) {
		String name = getCategoryName(langCode, posCode);
		if (StringUtil.isEmpty(name)) {
			return;
		}
		Element catList = ensureExist(model, model.getDocument()
				.getDocumentElement(), E_CATEGORY_LIST);
		NodeList cats = catList.getElementsByTagName(E_CATEGORY);
		boolean notFound = true;
		for (int i = 0; i < cats.getLength(); i++) {
			if (name.equals(((Element) cats.item(i)).getAttribute(
					A_CATEGORY_NAME).trim())) {
				notFound = false;
				break;
			}
		}
		if (notFound) {
			Element cat = model.getDocument().createElement(E_CATEGORY);
			cat.setAttribute(A_CATEGORY_NAME, name);
			model.appendChild(catList, cat);
		}
	}

	private void removeCategory(EntryModel model, String langCode,
			String posCode) {
		String name = getCategoryName(langCode, posCode);
		if (StringUtil.isEmpty(name)) {
			return;
		}
		Element catList = ensureExist(model, model.getDocument()
				.getDocumentElement(), E_CATEGORY_LIST);
		NodeList cats = catList.getElementsByTagName(E_CATEGORY);
		for (int i = 0; i < cats.getLength(); i++) {
			if (name.equals(((Element) cats.item(i)).getAttribute(
					A_CATEGORY_NAME).trim())) {
				model.remove(cats.item(i));
				break;
			}
		}
	}

	private Element ensureExist(EntryModel model, Element parent, String tag) {
		if (parent.getElementsByTagName(tag).getLength() <= 0) {
			model.appendChild(parent, model.getDocument().createElement(tag));
		}
		return (Element) parent.getElementsByTagName(tag).item(0);
	}

	private String getCategoryName(String langCode, String posCode) {
		String posName = MyArrays.translate(posCode, getPosCodes(),
				getPosNames());
		String langName = MyArrays.translate(langCode, getLanguageCodes(),
				getLanguageNames());
		return (posName != null && langName != null) ? posName + " "
				+ toLowerCaseFirstLetter(langName) : null;
	}

}
